﻿using Acr.UserDialogs;
using RaceHFTools.BluetoothLE.Bean;
using RaceHFTools.BluetoothLE.Bean.Module;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace RaceHFTools.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ManuTestPage : ContentPage
    {
        private readonly Bean bean;
        private uint pcode = 0;

        public ManuTestPage(Bean bean)
        {
            InitializeComponent();

            this.bean = bean;
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            Task.Run(async () =>
            {
                byte[] data = await Utils.Net.Download(Utils.Url.ProGetUrl(bean.Id));
                if (data != null && uint.TryParse(Encoding.ASCII.GetString(data), out pcode))
                    Device.BeginInvokeOnMainThread(() => lblPcode.Text = $"PCODE：{pcode}");
            });
        }

        async void Button_OpenAllPro_Clicked(object sender, EventArgs e)
        {
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.BATTERY, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GSENSOR, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GNSS, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.AGPS, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FLASH, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.SDCARD, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FSYNC, enable = true, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            UserDialogs.Instance.Toast("完成");
        }

        async void Button_OpenLimitPro_Clicked(object sender, EventArgs e)
        {
            bool battery = (pcode & (1 << 0)) != 0;
            bool gsensor = (pcode & (1 << 1)) != 0;
            bool gnss = (pcode & (1 << 2)) != 0;
            bool agps = (pcode & (1 << 3)) != 0;
            bool flash = (pcode & (1 << 4)) != 0;
            bool sdcard = (pcode & (1 << 5)) != 0;
            bool fsync = (pcode & (1 << 6)) != 0;

            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.BATTERY, enable = battery, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GSENSOR, enable = gsensor, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GNSS, enable = gnss, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.AGPS, enable = agps, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FLASH, enable = flash, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.SDCARD, enable = sdcard, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FSYNC, enable = fsync, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            UserDialogs.Instance.Toast("完成");
        }

        async void Button_CloseAllPro_Clicked(object sender, EventArgs e)
        {
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.BATTERY, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GSENSOR, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.GNSS, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.AGPS, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FLASH, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.SDCARD, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            await bean.Tweak.SetPro(new TweakProType { index = TweakProIndex.FSYNC, enable = false, validtime = 19951024 }, bean.Id, bean.LastPowerUtc);
            UserDialogs.Instance.Toast("完成");
        }

        async void Button_PowerOff_Clicked(object sender, EventArgs e)
        {
            await bean.Tweak.SetDevicePower(TweakDevicePowerMode.PowerOff);
        }

        void Button_PressTestFsync_Clicked(object sender, EventArgs e)
        {
            Task.Run(async () =>
            {
                int interval = int.Parse(etyInterval.Text);
                int test_total = 0, test_pass = 0;

                CancellationTokenSource cts = new CancellationTokenSource();
                var progress = UserDialogs.Instance.Progress("同步准备中", cts.Cancel, "[取消]");

                void show_process(string process, int percent)
                {
                    progress.Title = process;
                    progress.PercentComplete = percent;
                }

                do
                {
                    byte[] data = await bean.Fsync.SyncFile(@"/PTEST.BIN", show_process, cts.Token);
                    test_total++;
                    test_pass += data != null ? 1 : 0;
                    if (!cts.IsCancellationRequested)
                        PressTestShowLog(test_pass, test_total);

                    show_process("等待下轮运行", 0);
                    await Task.Delay(interval);
                } while (!cts.IsCancellationRequested);
            });
        }

        void Button_PressTestDfu_Clicked(object sender, EventArgs e)
        {
            Task.Run(async () =>
            {
                int interval = int.Parse(etyInterval.Text);
                int test_total = 0, test_pass = 0;

                CancellationTokenSource cts = new CancellationTokenSource();
                var progress = UserDialogs.Instance.Progress("固件准备中", cts.Cancel, "[取消]");

                void show_process(string process, int percent)
                {
                    progress.Title = process;
                    progress.PercentComplete = percent;
                }

                Utils.Url.URL_CHANNEL channel = Utils.Url.URL_CHANNEL.TEST;

                if (File.Exists(Utils.File.Firmware))
                    File.Delete(Utils.File.Firmware);

                string url = Utils.Url.GetOtaBinUrl(DFU_TYPE.FIRMWARE, channel, bean.Id);
                byte[] data = await Utils.Net.Download(url);
                if (data != null)
                    File.WriteAllBytes(Utils.File.Firmware, data);

                if (!File.Exists(Utils.File.Firmware))
                {
                    UserDialogs.Instance.Toast("固件下载失败");
                    return;
                }

                do
                {
                    bool success = await bean.Upgrade.Run(DFU_TYPE.FIRMWARE, File.ReadAllBytes(Utils.File.Firmware), show_process, cts.Token);
                    test_total++;
                    test_pass += success ? 1 : 0;
                    if (!cts.IsCancellationRequested)
                        PressTestShowLog(test_pass, test_total);

                    show_process("等待下轮运行", 0);
                    await Task.Delay(interval);
                } while (!cts.IsCancellationRequested);
            });
        }

        void PressTestShowLog(int pass, int total)
        {
            Device.BeginInvokeOnMainThread(() => lbPressTestLog.Text = $"{pass}/{total}");
        }
    }
}